package org.study.util;

import lombok.*;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;
import java.util.UUID;

/**
 * http://www.zzvips.com/article/73176.html
 *
 * @author Administrator
 * @date 2021-11-22
 */
public class ReadFileTests02 {
    public static void main(String[] args) throws FileNotFoundException {
        String pathName = "E:/data/20211123-test.bin";

        byte[] getContent = ReadFileTests02.getContent(pathName);
        // 每一次最多发送 200 字节，因此按大小拆分
        List<byte[]> byteArray = ArrayUtils.splitByteArray(getContent, 200);
        // 需要发送多少次
        int totalPackage = byteArray.size();
        // 协议文档要求：硬件版本为解析的bin文件从第28字节开始读取5个字节，软件版本为解析的bin文件从第33字节开始读取3个字节
        byte[] byte0 = byteArray.get(0);
        String hexString = ArrayUtils.bytesToHexString(byte0);
        System.out.println("byte[] 转十六进制：" + hexString);
        byte[] hardwareVer = new byte[5];
        System.arraycopy(byte0, 32, hardwareVer, 0, 5);
        byte[] softwareVer = new byte[3];
        System.arraycopy(byte0, 37, softwareVer, 0, 3);
        for (int i = 0; i < 10; i++) {
            // 针对每一个设备：假设有 10 个设备
            for (int index = 0; index < byteArray.size(); index++) {
                // 针对每一个数据帧
                Afn45Object afn45Object = new Afn45Object("45", "999999999", UUID.randomUUID().toString(), "CommNo-" + i, hardwareVer, softwareVer, byteArray.get(index), totalPackage, index);
                System.out.println(afn45Object);
            }
        }

        /*System.out.println(getContent.length);

        byte[] getContent2 = ReadFileTests02.getContent2(pathName);
        System.out.println(getContent2.length);

        byte[] toByteArray = ReadFileTests02.toByteArray(pathName);
        System.out.println(toByteArray.length);

        byte[] toByteArray2 = ReadFileTests02.toByteArray2(pathName);
        System.out.println(toByteArray2.length);

        byte[] toByteArray3 = ReadFileTests02.toByteArray3(pathName);
        System.out.println(toByteArray3.length);*/
    }

    public static byte[] getContent(String pathName) {
        File file = new File(pathName);
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            System.out.println("file too big...");
            return null;
        }
        byte[] buffer = null;
        try (FileInputStream fis = new FileInputStream(file)) {
            System.out.println("可从该输入流读取(或跳过)的剩余字节数：" + fis.available());
            buffer = new byte[(int) fileSize];
            int offset = 0;
            int numRead = 0;
            while (offset < buffer.length && (numRead = fis.read(buffer, offset, buffer.length - offset)) >= 0) {
                offset += numRead;
            }
            // 确保所有数据均被读取
            if (offset != buffer.length) {
                throw new IOException("Could not completely read file " + file.getName());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;
    }

    public static byte[] getContent2(String pathName) {
        byte[] bytes = null;
        try (FileInputStream fis = new FileInputStream(pathName);
             ByteArrayOutputStream baos = new ByteArrayOutputStream(1024)) {
            System.out.println("可从该输入流读取(或跳过)的剩余字节数：" + fis.available());
            byte[] temp = new byte[1024];
            int size = 0;
            while ((size = fis.read(temp)) != -1) {
                baos.write(temp, 0, size);
            }
            bytes = baos.toByteArray();
            return bytes;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return bytes;
        } catch (IOException e) {
            e.printStackTrace();
            return bytes;
        }
    }

    /**
     * the traditional io way
     *
     * @param pathName
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray(String pathName) throws FileNotFoundException {
        File file = new File(pathName);
        /*if (!file.exists()) {
            throw new FileNotFoundException(pathName);
        }*/
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis);
             ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length())) {
            System.out.println("可从该输入流读取(或跳过)的剩余字节数：" + fis.available());
            int bufSize = 1024;
            byte[] buffer = new byte[bufSize];
            int len = 0;
            while (-1 != (len = bis.read(buffer, 0, bufSize))) {
                bos.write(buffer, 0, len);
            }
            byte[] byteArray = bos.toByteArray();
            return byteArray;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * NIO way
     *
     * @param pathName
     * @return
     * @throws IOException
     */
    public static byte[] toByteArray2(String pathName) throws FileNotFoundException {
        File file = new File(pathName);
        /*if (!file.exists()) {
            throw new FileNotFoundException(pathName);
        }*/
        try (FileInputStream fis = new FileInputStream(file);
             FileChannel channel = fis.getChannel()) {
            System.out.println("可从该输入流读取(或跳过)的剩余字节数：" + fis.available());
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            while ((channel.read(byteBuffer)) > 0) {
                // do nothing
                //System.out.println("reading");
            }
            return byteBuffer.array();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * Mapped File way MappedByteBuffer 可以在处理大文件时，提升性能
     *
     * @param pathName
     * @return byte[]
     */
    public static byte[] toByteArray3(String pathName) {
        try (RandomAccessFile raf = new RandomAccessFile(pathName, "r");
             FileChannel fc = raf.getChannel()) {
            MappedByteBuffer mappedByteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load();
            System.out.println(mappedByteBuffer.isLoaded());
            byte[] result = new byte[(int) fc.size()];
            if (mappedByteBuffer.remaining() > 0) {
                // System.out.println("remain");
                mappedByteBuffer.get(result, 0, mappedByteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

/**
 * 远程升级下发升级包指令
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
class Afn45Object implements Serializable {
    private static final long serialVersionUID = 4691902693941089275L;

    private String afn;
    private String jzqAddr;
    private String queueGuid;
    private String moteEUI;
    private byte[] hardwareVer;
    private byte[] softwareVer;
    private byte[] dataArea;
    private int totalPackage;
    private int indexPackage;
}